﻿using CommunityToolkit.Mvvm.ComponentModel;
using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Company.Hardware
{
    /* 
         * 型号：XK3190-A9
         * 公司：上海耀华称重系统有限公司
         * 说明：
         *       XK3190－A9仪表具有RS232/RS422(选配)串行通讯接口，可与计算机进行通讯。
         *       1．通讯接口采用15芯RS232插头座(与大屏幕共用)，
         *          其引脚定义见图2－5中6、7、8脚 (RS232)或1、2、3、4脚(RS422)。
         *       2. 所有数据均为ASCII码，每组数据有10位组成，第1位为起始位，第10位为停止位，中间8位为数据位。
         *       3. 所传送的数据为仪表显示的当前称量(毛重或净重)。每帧数据由12组数据组成 。
         *       
         *        第X字节	内  容  及  注  解
                    1	   02(XON)                  开始  
                    2	   +或-                     符号位
                    3	   称量数据                 高位
                    4	   称量数据                  .
                    5	   称量数据                  .
                    6	   称量数据                  .
                    7	   称量数据                  .
                    8	   称量数据                 低位                      
                    9	   小数点位数           从右到左（0～4）
                    10	   异或校验                 高四位   
                    11	   异或校验                 低四位
                    12	   03(X0FF)                 结束

                 4.异或＝2⊕3⊕……8⊕9  总长度 12个字节

                      02 2B 30 30 38 39 37 30 30 31 44 03

                      02 2B 30 30 38 39 39 30 30 31 44 05
         */
    public class Scale :  ObservableObject, IScale
    {
        private Task _task;
        private SerialPort serialPort;
        private bool _initialized;
        private bool _connected;
        private string _hex;
        private string _message;
        private double _value;
        private double _triggerValue=0;


        public bool Initialized { get => _initialized; set => SetProperty(ref _initialized, value); }
        public bool Connected { get => _connected; set => SetProperty(ref _connected, value); }
        public string Hex { get => _hex; set => SetProperty(ref _hex, value); }
        public string Message { get => _message; set => SetProperty(ref _message, value); }
        public double Value { get => _value; set => SetProperty(ref _value, value); }

        public event Action<string> MessageChanged;
        public event Action<double> ValueChanged;

        public bool Close()
        {
            serialPort.Close();
            serialPort.Dispose();
            serialPort = null;
            Initialized= false;
            return true;
        }

        public bool Init(string portName, int baudRate)
        {
            if (!Initialized)
            {
                serialPort = new SerialPort(portName, baudRate);
                serialPort.ReceivedBytesThreshold = 1;
                serialPort.DataReceived += SerialPort_DataReceived;
                Initialized = true;
                return Initialized;
            }
            else
            {
                return false;
            }
        }

        private void SerialPort_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
            try
            {
                byte[] data = new byte[12];
                int count = 1;
                while(count < data.Length)
                {
                    // 每次只取一个字节
                    byte receive = (byte)serialPort.ReadByte();
                    // 找头部
                    if (data[0] != 0x02 || receive == 0x02)
                    {
                        data[0] = receive;
                    }
                    else
                    {
                        data[count++] = receive;
                    }
                }

                // 获取HEX源码
                Hex = string.Empty;
                for (int i = 0; i < data.Length; i++)
                {
                    Hex += data[i].ToString() + " ";
                }

                // 异或校验
                byte a = 0;
                for (int i = 1; i < 9; i++)
                {
                    a ^= data[i];
                }

                string sum = "0000000" + Convert.ToString(a, 2);
                sum = sum.Substring(sum.Length - 8, 8);
                string high = sum.Substring(0, 4);
                high = Convert.ToString(Convert.ToInt32(high, 2), 16);
                high = high.ToUpper();
                string low = sum.Substring(4, 4);
                low = Convert.ToString(Convert.ToInt32(low,2), 16);
                low = low.ToUpper();
                ASCIIEncoding asc= new ASCIIEncoding();
                high = asc.GetBytes(high)[0].ToString("X2");
                low = asc.GetBytes(low)[0].ToString("X2");
                if(high == data[9].ToString("X2") && low == data[10].ToString("X2"))
                {
                    Message = "校验成功";
                    // 符号位
                    string symbol = ((char)data[1]).ToString();
                    // 仪表值
                    string value = string.Empty;
                    for (int i = 2; i < 8; i++)
                    {
                        value += ((char)data[i]).ToString();
                    }
                    // 小数点
                    int position = int.Parse(((char)data[8]).ToString());
                    // 插入小数点
                    if (position > 0)
                    {
                        value = value.Insert(6 - position, ".");
                    }
                    string display;
                    if (symbol == "-")
                    {
                        display = symbol + value.TrimStart('0');
                    }
                    else
                    {
                        display = value.TrimStart('0');
                    }
                    // 全部显示0
                    if(display.Length == 0)
                    {
                        display = "0";
                    }
                    if(double.TryParse(display, out double result))
                    {
                        Value = result;
                    }
                    ValueChanged?.Invoke(Value);
                    Message = $"通讯正常 | 时间：{DateTime.Now.ToLongTimeString()}";
                    Connected = true;
                }
                else
                {
                    Message = "校验失败";
                    Value = 0;
                }
            }
            catch (Exception ex)
            {

                MessageChanged?.Invoke(ex.Message);
                Value = 0;
                Connected= false;
            }
        }

        public bool Open()
        {
            try
            {
                if (Initialized)
                {
                    serialPort.Open();
                }
                Connected= true;
                return true;
            }
            catch (Exception ex)
            {
                MessageChanged?.Invoke(ex.Message);
                return false;
            }
        }

        public void Trigger(double value)
        {
            _triggerValue = value;
            if (_task == null)
            {
                _task = Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        Task.Delay(50).Wait();
                        Value = _triggerValue;
                        ValueChanged?.Invoke(Value);
                    }
                });
            }
        }
    }
}
